﻿// -----------------------------------------------------------------------
// <copyright company="Christoph van der Fecht - VDsoft">
// This code can be used in commercial, free and open source projects.
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GalaSoft.MvvmLight;
using VDsoft.SeriesNewsReader.Model;
using System.Collections.ObjectModel;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Newtonsoft.Json;

namespace VDsoft.SeriesNewsReader.ViewModel
{
	/// <summary>
	/// ViewModel for the main view.
	/// </summary>
	public class MainViewModel : ViewModelBase
	{
		/// <summary>
		/// Default title for the window.
		/// </summary>
		private const string DefaultTitle = "Series News Reader V2";

		/// <summary>
		/// The Series.
		/// </summary>
		private ObservableCollection<RssFeed> series = new ObservableCollection<RssFeed>();

		/// <summary>
		/// The Languages.
		/// </summary>
		private ObservableCollection<string> languages = new ObservableCollection<string>();
		
		/// <summary>
		/// The FilterHdReady.
		/// </summary>
		private bool filterHdReady = false;

		/// <summary>
		/// The FilterFullHd.
		/// </summary>
		private bool filterFullHd = false;

		/// <summary>
		/// The SelectedLanguage.
		/// </summary>
		private string selectedLanguage;

		/// <summary>
		/// Collection of all monitored series.
		/// </summary>
		private ObservableCollection<string> monitoredSeries = new ObservableCollection<string>();

		/// <summary>
		/// Currently set search criteria.
		/// </summary>
		private string searchCriteria = null;

		/// <summary>
		/// Title of the application.
		/// </summary>
		private string title = DefaultTitle;

		#region private commands

		/// <summary>
		/// Command to show the options dialog.
		/// </summary>
		private RelayCommand showOptionsCommand = null;

		/// <summary>
		/// Command to apply a series filter.
		/// </summary>
		private RelayCommand<string> applySeriesFilterCommand = null;

		/// <summary>
		/// Command to show the about dialog.
		/// </summary>
		private RelayCommand showAboutDialogCommand = null;

		#endregion

		/// <summary>
		/// Initializes a new instance of the <see cref="MainViewModel"/> class.
		/// </summary>
		public MainViewModel()
		{
			if (this.IsInDesignMode)
			{
				List<RssFeed> dummy = new List<RssFeed>();
				for (int seriesCounter = 0; seriesCounter < 10; seriesCounter++)
				{
					string language = string.Empty;
					if (seriesCounter % 2 == 0)
					{
						language = "English";
					}
					else
					{
						language = "Germany";
					}

					dummy.Add(new RssFeed
						{
							Title = string.Concat("Title ", seriesCounter),
							Language = language,
							Link = new Uri(string.Concat("http://www.test.com/", seriesCounter))
						});
				}

				this.Series = new ObservableCollection<RssFeed>(dummy);

				this.Languages = new ObservableCollection<string>(new List<string>()
				{
					"English",
					"German"
				});

                this.FilterFullHd = true;
				this.FilterHdReady = true;
			}
			else
			{
				Properties.Settings.Default.SettingsSaving += this.OnSettingsSaving;
				Repository.SeriesRepository.Instance.InitRepo();
				Messenger.Default.Register<List<RssFeed>>(this, ViewModelLocator.SeriesFilterResult, this.OnReceiveFilterResult);
				Messenger.Default.Register<List<string>>(this, ViewModelLocator.LanguageToken, this.OnLanguagesReceived);

				this.UpdateMonitoredSeries();
				RssLoader.Instance.LoadSeries();
			}
		}

		/// <summary>
		/// Gets or sets the Series.
		/// </summary>
		public ObservableCollection<RssFeed> Series
		{
			get
			{
				return this.series;
			}

			set
			{
				if (value == this.series)
				{
					return;
				}

				this.series = value;
				this.RaisePropertyChanged("Series");
			}
		}

		/// <summary>
		/// Gets or sets the Languages.
		/// </summary>
		public ObservableCollection<string> Languages
		{
			get
			{
				return this.languages;
			}

			set
			{
				if (value == this.languages)
				{
					return;
				}

				this.languages = value;
				this.RaisePropertyChanged("Languages");
			}
		}

		/// <summary>
		/// Gets or sets the SelectedLanguage.
		/// </summary>
		public string SelectedLanguage
		{
			get
			{
				return this.selectedLanguage;
			}

			set
			{
				if (value == this.selectedLanguage)
				{
					return;
				}

				this.selectedLanguage = value;
				this.RaisePropertyChanged("SelectedLanguage");
				////Repository.SeriesRepository.Instance.ApplyLanguageFilter(value);
				this.ApplyFilter();
			}
		}

		/// <summary>
		/// Gets or sets the FilterHdReady.
		/// </summary>
		public bool FilterHdReady
		{
			get
			{
				return this.filterHdReady;
			}

			set
			{
				if (value == this.filterHdReady)
				{
					return;
				}

				this.filterHdReady = value;
				this.RaisePropertyChanged("FilterHdReady");
				////this.ApplyReslutionFilter();
				this.ApplyFilter();
			}
		}

		/// <summary>
		/// Gets or sets the FilterFullHd.
		/// </summary>
		public bool FilterFullHd
		{
			get
			{
				return this.filterFullHd;
			}

			set
			{
				if (value == this.filterFullHd)
				{
					return;
				}

				this.filterFullHd = value;
				this.RaisePropertyChanged("FilterFullHd");
				////this.ApplyReslutionFilter();
				this.ApplyFilter();
			}
		}

		/// <summary>
		/// Gets or sets the collection of monitored series.
		/// </summary>
		public ObservableCollection<string> MonitoredSeries
		{
			get
			{
				return this.monitoredSeries;
			}

			set
			{
				if (value == this.monitoredSeries)
				{
					return;
				}

				this.monitoredSeries = value;
				this.RaisePropertyChanged("MonitoredSeries");
			}
		}

		/// <summary>
		/// Gets or sets the title of the application.
		/// </summary>
		public string Title
		{
			get 
			{
				return this.title;
			}

			set
			{
				if (value == this.title)
				{
					return;
				}

				this.title = value;
				this.RaisePropertyChanged("Title");
			}
		}

		#region public commands

		/// <summary>
		/// Gets the command to show the options dialog.
		/// </summary>
		public RelayCommand ShowOptionsCommand
		{
 			get
			{
				if (this.showOptionsCommand == null)
				{
					this.showOptionsCommand = new RelayCommand(this.ShowOptionsDialog);
				}

				return this.showOptionsCommand;
			}
		}

		/// <summary>
		/// Gets the command to apply a filter criteria.
		/// </summary>
		public RelayCommand<string> ApplySeriesFilterCommand
		{
			get
			{
				if (this.applySeriesFilterCommand == null)
				{
					this.applySeriesFilterCommand = new RelayCommand<string>(this.ApplySeriesFilter);
				}

				return this.applySeriesFilterCommand;
			}
		}

		/// <summary>
		/// Gets the command to show the about dialog.
		/// </summary>
		public RelayCommand ShowAboutDialogCommand
		{
			get
			{
				if (this.showAboutDialogCommand == null)
				{
					this.showAboutDialogCommand = new RelayCommand(this.ShowAboutDialog);
				}

				return this.showAboutDialogCommand;
			}
		}

		#endregion

		/// <summary>
		/// Shows the options dialog.
		/// </summary>
		private void ShowOptionsDialog()
		{
			Options dialog = new Options();
			dialog.ShowDialog();
		}

		/// <summary>
		/// Receives all available languages.
		/// </summary>
		/// <param name="languages">Collection of all available languages.</param>
		private void OnLanguagesReceived(List<string> languages)
		{
			this.Languages = new ObservableCollection<string>(languages);
		}

		/// <summary>
		/// Receives the filter result.
		/// </summary>
		/// <param name="filterResult">Result of a filter request.</param>
		private void OnReceiveFilterResult(List<RssFeed> filterResult)
		{
			this.Series = new ObservableCollection<RssFeed>(filterResult);
		}

		/// <summary>
		/// Receives all loaded series.
		/// </summary>
		/// <param name="allSeries">All series.</param>
		private void OnReceivedSeries(List<RssFeed> allSeries)
		{
			this.Series = new ObservableCollection<RssFeed>(allSeries);
		}

		/// <summary>
		/// Applys a filter with the provided criteria.
		/// </summary>
		/// <param name="criteria">Criteria to filter.</param>
		private void ApplySeriesFilter(string criteria)
		{
			if (string.IsNullOrEmpty(criteria))
			{
				return;
			}

			////Repository.SeriesRepository.Instance.ApplyFilter(criteria);
			this.searchCriteria = criteria;
			this.Title = string.Concat(DefaultTitle, " - ", criteria);
			this.ApplyFilter();
		}

		/// <summary>
		/// Applys the filter of the resolution.
		/// </summary>
		private void ApplyReslutionFilter()
		{
			if (this.filterFullHd && this.filterHdReady)
			{
				Repository.SeriesRepository.Instance.ApplyReslutionFilter(Resolution.All);
			}
			else if (this.filterFullHd)
			{
				Repository.SeriesRepository.Instance.ApplyReslutionFilter(Resolution.FullHD);
			}
			else if (this.filterHdReady)
			{
				Repository.SeriesRepository.Instance.ApplyReslutionFilter(Resolution.HDReady);
			}
			else
			{
				Repository.SeriesRepository.Instance.ApplyReslutionFilter(Resolution.All);
				this.filterHdReady = false;
				this.filterFullHd = false;
				this.RaisePropertyChanged("FilterFullHd");
				this.RaisePropertyChanged("FilterHdReady");
			}
		}

		/// <summary>
		/// Applyes the filter with all criterieas.
		/// </summary>
		private void ApplyFilter()
		{
			SearchCriteria criteria = new SearchCriteria();

			if (!string.IsNullOrEmpty(this.searchCriteria))
			{
				criteria.SearchString = this.searchCriteria;
			}

			if (!string.IsNullOrEmpty(this.selectedLanguage))
			{
				criteria.Language = this.selectedLanguage;
			}

			if (this.filterFullHd && this.filterHdReady)
			{
				criteria.Resolution = Resolution.HD;
			}
			else if (this.filterFullHd)
			{
				criteria.Resolution = Resolution.FullHD;
			}
			else if (this.filterHdReady)
			{
				criteria.Resolution = Resolution.HDReady;
			}
			else
			{
				criteria.Resolution = Resolution.All;
			}

			Repository.SeriesRepository.Instance.ApplyFilter(criteria);
		}

		/// <summary>
		/// Reloads the monitored series.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void OnSettingsSaving(object sender, System.ComponentModel.CancelEventArgs e)
		{
			this.UpdateMonitoredSeries();
		}

		/// <summary>
		/// Updates the collection of monitored series.
		/// </summary>
		private void UpdateMonitoredSeries()
		{
			List<string> update = JsonConvert.DeserializeObject<List<string>>(Properties.Settings.Default.Series);

			if (update != null)
			{
				this.MonitoredSeries = new ObservableCollection<string>(update);
			}
		}

		/// <summary>
		/// Shows the about dialog.
		/// </summary>
		private void ShowAboutDialog()
		{
			AboutDialog dialog = new AboutDialog();
			dialog.ShowInTaskbar = false;
			dialog.ShowDialog();
		}
	}
}
